﻿#include "MapInfo.h"
#include "../MirEnvir/Map.h"

using namespace Server::MirEnvir;

namespace Server::MirDatabase
{

    Server::MirEnvir::Envir *MapInfo::getEnvir()
    {
        return Envir::getMain();
    }

    Server::MirEnvir::Envir *MapInfo::getEditEnvir()
    {
        return getEnvir()->Edit;
    }

    MapInfo::MapInfo()
    {

    }

    MapInfo::MapInfo(BinaryReader *reader)
    {
        Index = reader->ReadInt32();
        FileName = reader->ReadString();
        Title = reader->ReadString();
        MiniMap = reader->ReadUInt16();
        Light = static_cast<LightSetting>(reader->ReadByte());

        BigMap = reader->ReadUInt16();

        int count = reader->ReadInt32();
        for (int i = 0; i < count; i++)
        {
            SafeZoneInfo *tempVar = new SafeZoneInfo(reader);
            tempVar->Info = this;
            SafeZones.push_back(tempVar);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
        }

        count = reader->ReadInt32();
        for (int i = 0; i < count; i++)
        {
            RespawnInfo tempVar2(reader, Envir::LoadVersion, Envir::LoadCustomVersion);
            Respawns.push_back(&tempVar2);
        }

        count = reader->ReadInt32();
        for (int i = 0; i < count; i++)
        {
            MovementInfo tempVar3(reader);
            Movements.push_back(&tempVar3);
        }

        NoTeleport = reader->ReadBoolean();
        NoReconnect = reader->ReadBoolean();
        NoReconnectMap = reader->ReadString();

        NoRandom = reader->ReadBoolean();
        NoEscape = reader->ReadBoolean();
        NoRecall = reader->ReadBoolean();
        NoDrug = reader->ReadBoolean();
        NoPosition = reader->ReadBoolean();
        NoThrowItem = reader->ReadBoolean();
        NoDropPlayer = reader->ReadBoolean();
        NoDropMonster = reader->ReadBoolean();
        NoNames = reader->ReadBoolean();
        Fight = reader->ReadBoolean();
        Fire = reader->ReadBoolean();
        FireDamage = reader->ReadInt32();
        Lightning = reader->ReadBoolean();
        LightningDamage = reader->ReadInt32();
        MapDarkLight = reader->ReadByte();
        count = reader->ReadInt32();
        for (int i = 0; i < count; i++)
        {
            MineZone tempVar4(reader);
            MineZones.push_back(&tempVar4);
        }
        MineIndex = reader->ReadByte();
        NoMount = reader->ReadBoolean();
        NeedBridle = reader->ReadBoolean();
        NoFight = reader->ReadBoolean();
        Music = reader->ReadUInt16();

        if (Envir::LoadVersion < 78)
        {
            return;
        }
        NoTownTeleport = reader->ReadBoolean();
        if (Envir::LoadVersion < 79)
        {
            return;
        }
        NoReincarnation = reader->ReadBoolean();
    }

    void MapInfo::Save(BinaryWriter *writer)
    {
        writer->Write(Index);
        writer->Write(FileName);
        writer->Write(Title);
        writer->Write(MiniMap);
        writer->Write(static_cast<unsigned char>(Light));
        writer->Write(BigMap);
        writer->Write(SafeZones.size());

        for (int i = 0; i < SafeZones.size(); i++)
        {
            SafeZones[i]->Save(writer);
        }

        writer->Write(Respawns.size());
        for (int i = 0; i < Respawns.size(); i++)
        {
            Respawns[i]->Save(writer);
        }

        writer->Write(Movements.size());
        for (int i = 0; i < Movements.size(); i++)
        {
            Movements[i]->Save(writer);
        }

        writer->Write(NoTeleport);
        writer->Write(NoReconnect);
        writer->Write(NoReconnectMap);
        writer->Write(NoRandom);
        writer->Write(NoEscape);
        writer->Write(NoRecall);
        writer->Write(NoDrug);
        writer->Write(NoPosition);
        writer->Write(NoThrowItem);
        writer->Write(NoDropPlayer);
        writer->Write(NoDropMonster);
        writer->Write(NoNames);
        writer->Write(Fight);
        writer->Write(Fire);
        writer->Write(FireDamage);
        writer->Write(Lightning);
        writer->Write(LightningDamage);
        writer->Write(MapDarkLight);
        writer->Write(MineZones.size());
        for (int i = 0; i < MineZones.size(); i++)
        {
            MineZones[i]->Save(writer);
        }
        writer->Write(MineIndex);

        writer->Write(NoMount);
        writer->Write(NeedBridle);

        writer->Write(NoFight);

        writer->Write(Music);
        writer->Write(NoTownTeleport);
        writer->Write(NoReincarnation);

    }

    void MapInfo::CreateMap()
    {
        for (int j = 0; j < getEnvir()->NPCInfoList.size(); j++)
        {
            if (getEnvir()->NPCInfoList[j]->MapIndex != Index)
            {
                continue;
            }

            NPCs.push_back(getEnvir()->NPCInfoList[j]);
        }

        Map *map = new Map(this);

        if (!map->Load())
        {
            delete map;
            return;
        }

        getEnvir()->MapList.push_back(map);

        for (int i = 0; i < SafeZones.size(); i++)
        {
            if (SafeZones[i]->StartPoint)
            {
                getEnvir()->StartPoints.push_back(SafeZones[i]);
            }
        }

//C# TO C++ CONVERTER TODO TASK: A 'delete map' statement was not added since map was passed to a method or constructor. Handle memory management manually.
    }

    void MapInfo::CreateSafeZone()
    {
        SafeZoneInfo *tempVar = new SafeZoneInfo();
        tempVar->Info = this;
        SafeZones.push_back(tempVar);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
    }

    void MapInfo::CreateRespawnInfo()
    {
        RespawnInfo *tempVar = new RespawnInfo();
        setEditEnvir(getEditEnvir() + 1);
        tempVar->RespawnIndex = getEditEnvir()->RespawnIndex;
        Respawns.push_back(tempVar);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
    }

    std::string MapInfo::ToString()
    {
        return StringHelper::formatSimple("{0}: {1}", Index, Title);
    }

    void MapInfo::CreateNPCInfo()
    {
        NPCInfo tempVar();
        NPCs.push_back(&tempVar);
    }

    void MapInfo::CreateMovementInfo()
    {
        MovementInfo tempVar();
        Movements.push_back(&tempVar);
    }

    void MapInfo::FromText(const std::string &text)
    {
        std::vector<std::string> data = text.Split({','}, StringSplitOptions::RemoveEmptyEntries);

        if (data.size() < 8)
        {
            return;
        }

        MapInfo *info = new MapInfo();
        info->FileName = data[0];
        info->Title = data[1];


        if (!unsigned short::TryParse(data[2], info->MiniMap))
        {
            delete info;
            return;
        }

        if (!Enum::TryParse(data[3], info->Light))
        {
            delete info;
            return;
        }
        int sziCount, miCount, riCount, npcCount;

        if (!int::TryParse(data[4], sziCount))
        {
            delete info;
            return;
        }
        if (!int::TryParse(data[5], miCount))
        {
            delete info;
            return;
        }
        if (!int::TryParse(data[6], riCount))
        {
            delete info;
            return;
        }
        if (!int::TryParse(data[7], npcCount))
        {
            delete info;
            return;
        }


        int start = 8;

        for (int i = 0; i < sziCount; i++)
        {
            SafeZoneInfo *temp = new SafeZoneInfo();
            temp->Info = info;
            int x, y;

            if (!int::TryParse(data[start + (i * 4)], x))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!int::TryParse(data[start + 1 + (i * 4)], y))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!unsigned short::TryParse(data[start + 2 + (i * 4)], temp->Size))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!bool::TryParse(data[start + 3 + (i * 4)], temp->StartPoint))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }

            temp->Location = new Point(x, y);
            info->SafeZones.push_back(temp);

//C# TO C++ CONVERTER TODO TASK: A 'delete temp' statement was not added since temp was passed to a method or constructor. Handle memory management manually.
        }
        start += sziCount * 4;



        for (int i = 0; i < miCount; i++)
        {
            MovementInfo *temp = new MovementInfo();
            int x, y;

            if (!int::TryParse(data[start + (i * 5)], x))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!int::TryParse(data[start + 1 + (i * 5)], y))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            temp->Source = new Point(x, y);

            if (!int::TryParse(data[start + 2 + (i * 5)], temp->MapIndex))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }

            if (!int::TryParse(data[start + 3 + (i * 5)], x))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!int::TryParse(data[start + 4 + (i * 5)], y))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            temp->Destination = new Point(x, y);

            info->Movements.push_back(temp);

//C# TO C++ CONVERTER TODO TASK: A 'delete temp' statement was not added since temp was passed to a method or constructor. Handle memory management manually.
        }
        start += miCount * 5;


        for (int i = 0; i < riCount; i++)
        {
            RespawnInfo *temp = new RespawnInfo();
            int x, y;

            if (!int::TryParse(data[start + (i * 7)], temp->MonsterIndex))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!int::TryParse(data[start + 1 + (i * 7)], x))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!int::TryParse(data[start + 2 + (i * 7)], y))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }

            temp->Location = new Point(x, y);

            if (!unsigned short::TryParse(data[start + 3 + (i * 7)], temp->Count))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!unsigned short::TryParse(data[start + 4 + (i * 7)], temp->Spread))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!unsigned short::TryParse(data[start + 5 + (i * 7)], temp->Delay))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!unsigned char::TryParse(data[start + 6 + (i * 7)], temp->Direction))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!int::TryParse(data[start + 7 + (i * 7)], temp->RespawnIndex))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!bool::TryParse(data[start + 8 + (i * 7)], temp->SaveRespawnTime))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!unsigned short::TryParse(data[start + 9 + (i * 7)], temp->RespawnTicks))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }

            info->Respawns.push_back(temp);

//C# TO C++ CONVERTER TODO TASK: A 'delete temp' statement was not added since temp was passed to a method or constructor. Handle memory management manually.
        }
        start += riCount * 7;


        for (int i = 0; i < npcCount; i++)
        {
            NPCInfo *temp = new NPCInfo();
            temp->FileName = data[start + (i * 6)];
            temp->Name = data[start + 1 + (i * 6)];
            int x, y;

            if (!int::TryParse(data[start + 2 + (i * 6)], x))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!int::TryParse(data[start + 3 + (i * 6)], y))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }

            temp->Location = new Point(x, y);

            if (!unsigned short::TryParse(data[start + 4 + (i * 6)], temp->Rate))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }
            if (!unsigned short::TryParse(data[start + 5 + (i * 6)], temp->Image))
            {
                delete temp;
//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
                return;
            }

            info->NPCs.push_back(temp);

//C# TO C++ CONVERTER TODO TASK: A 'delete temp' statement was not added since temp was passed to a method or constructor. Handle memory management manually.
        }



        setEditEnvir(getEditEnvir() + 1);
        info->Index = getEditEnvir()->MapIndex;
        getEditEnvir()->MapInfoList.push_back(info);

//C# TO C++ CONVERTER TODO TASK: A 'delete info' statement was not added since info was assigned to a field. Handle memory management manually.
    }
}
